﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MMITWeb.Infrastructure.Abstract;
using System.Web.Security;
using MMITDomain.Entities;
using MMITDomain.Abstract;
using MMITCore.Logging;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using System.Text;
using MMITCore.Abstract;
using MMITWeb.Models;


namespace MMITWeb.Infrastructure.Concrete
{
    public class FormsAuthProvider : IAuthProvider
    {
        ICustomerRepository custrepository;
        ILogger<SynkronLogger> _logger;
        ITransactionRoleRepository transactionRoleRepository;
        ITransactionRoleAccountRepository transactionRoleAccountRepository;
        ICountryRepository countryRepository;
        INotificationManager notificationManager;

        public FormsAuthProvider(ICustomerRepository customerRepository, ITransactionRoleRepository transactionRoleRepository,ILogger<SynkronLogger> logger,
            ITransactionRoleAccountRepository transactionRoleAccountRepository, ICountryRepository countryRepository, INotificationManager notificationManager)
        {
            custrepository = customerRepository;
            
            this.transactionRoleRepository = transactionRoleRepository;
            this.transactionRoleAccountRepository = transactionRoleAccountRepository;
            this.countryRepository = countryRepository;
            this.notificationManager = notificationManager;
            _logger = logger;
        }
        
        #region IAuthProvider Members

        public bool Authenticate(string Username, string Password)
        {
            bool result = Membership.ValidateUser(Username, Password);
           
                if (result)
                {
                    FormsAuthentication.SetAuthCookie(Username, false);
                }

                return result;
        }

        


        public bool Register(string Username, string Password, string Email, string Firstname, string Middlename, 
            string Lastname, string Mobile, string Sex, int CountryId, int IdentificationTypeId,string IdentificationNumber,
            out string strErrorCode)
        {
            // Attempt to register the user
            strErrorCode = "";
            try
            {
                //First Check the MSISDN has not been used before 
                var c = custrepository.GetCustomerByMSISDN(Mobile);
                if (c != null)
                {
                    strErrorCode = "A User with this Mobile Number exists";
                    _logger.WriteError(5000000, () => "User Registration Failure", new Dictionary<string, object> { { strErrorCode, _logger.Desc(c) }}); 
                    return false;
                }

                MembershipCreateStatus createStatus;
                Membership.CreateUser(Username, Password, Email, null, null, true, null, out createStatus);
                
                strErrorCode = createStatus == MembershipCreateStatus.Success ? "User Account Created Sucessfully" : ErrorCodeToString(createStatus);

                if (createStatus == MembershipCreateStatus.Success)
                {
                    try
                    {
                        //Add User to Customer Role
                        Roles.AddUserToRole(Username, "Customer");

                        //create customer 
                        var objCustomer = new Customer
                        {
                            Firstname = Firstname,
                            Middlename = Middlename,
                            Lastname = Lastname,
                            Username = Username,
                            Sex = Sex,
                            Mobile = Mobile,
                            CountryId = CountryId,
                            IdentificationTypeId = IdentificationTypeId,
                            IdentificationNumber = IdentificationNumber,
                            DateCreated = DateTime.Now
                        };

                        //Create Default Account  for Customer
                        var objAccount = new Account
                        {
                            Customer = objCustomer,
                            AccountTypeId = (int)AccountType.AccountTypes.Customer,
                            ActualBalance = 0.00M,
                            AvailableBalance = 0.00M,
                            CurrencyId = countryRepository.GetDefaultCurrency(countryRepository.GetCountryById(CountryId)).Id,
                            Status = (int)AccountStatuses.Active,
                            Name = Mobile.ToString()
                        };

                        //Add user account to Transaction Role Account of Type Customer.
                        TransactionRoleAccount objTransactionRoleAccount = new TransactionRoleAccount
                        {
                            Account = objAccount,
                            TransactionRoleId = transactionRoleRepository.GetTransactionRoleByName("Customer Transactions").Id
                        };

                        // Save transaction role account.. this method also persists all other objects => Account, Customer and Transaction Role
                        // through Entity Framework's Db Context..
                        transactionRoleAccountRepository.SaveTransactionRoleAccount(objTransactionRoleAccount);

                        FormsAuthentication.SetAuthCookie(Username, false /* createPersistentCookie */);

                        //Notify customer account details to customer..
                        notificationManager._notificationType = NotificationType.EmailNotification;
                        
                       //string content = string.Format("Dear {0} Thank you for registering with m-Diaspora, Please find your login details below: Username: {1}  Password: {2}  please visit mdiaspora website to login to your member area", objCustomer.Firstname, objCustomer.Username, Password);
                       // notificationManager.SendPlainEmail(new string[] { Email }, "webmaster@mmitonline.com", "webmaster", "m-Diaspora Login Information", content);

                        var model = new EmailViewModel{ from="webmaster@mmitonline.com", subject= "m-Diaspora Login Information", to = new string[] { Email }, 
                            from_alias="webmaster", firstname=objCustomer.Firstname, lastname=objCustomer.Lastname, password = Password, username=objCustomer.Username};
                       
                        notificationManager.SendTemplateEmail(EmailType._Registration,model);
                       
                        _logger.WriteInformation(5000001, () => "User Account Created Sucessfully", new Dictionary<string, object> { { "User Info: ", _logger.Desc(objCustomer) }, 
                            { "Account Info: ", _logger.Desc(objAccount) } 
                        });
                    }
                    catch (Exception Ex)
                    {
                        _logger.WriteError(5000002, () => "User Registration Exception", Ex, new Dictionary<string, object> { { strErrorCode, _logger.Desc(this) } }); 
                    }
                    return true;
                }
                else
                {
                    var userInfo = new { FName = Firstname, MName = Middlename, LName = Lastname, MSISDN = Mobile, UName=Username, Email = Email};
                    _logger.WriteError(5000003, () => "User Registration Failure", new Dictionary<string, object> { { strErrorCode, _logger.Desc(userInfo) } }); 
                }
            }
            catch (Exception Ex)
            {
                _logger.WriteError(5000004, () => "User Registration Exception", Ex, new Dictionary<string, object> { { strErrorCode, _logger.Desc(this) } }); 
            }

            return false;
        }

        public void LogOff()
        {
            FormsAuthentication.SignOut();
        }

        public bool ChangePassword(string Username, string OldPassword, string NewPassword)
        {
            // ChangePassword will throw an exception rather
            // than return false in certain failure scenarios.
            try
            {
                MembershipUser currentUser = Membership.GetUser(Username, true /* userIsOnline */);

                _logger.WriteInformation(5000005, () => "User Password Updated Sucessfully", new Dictionary<string, object> { { "User Info: ", _logger.Desc(currentUser) }
                        });
                return currentUser.ChangePassword(OldPassword, NewPassword);
            }
            catch (Exception Ex)
            {
                _logger.WriteError(5000006, string.Format("User Password Update Failure | User: {0}", Username), Ex);              
            }

            return false;  
        }

        public string GetUserEmail(string Username)
        {
            try
            {
                var user = Membership.GetUser(Username);
                return user.Email;
            }
            catch (Exception Ex)
            {
                _logger.WriteError(5000007, string.Format("Get User Email Failure | User: {0}", Username), Ex);
                throw;
            }
        }

        public void UpdateUserEmail(string Username, string Email)
        {
            try
            {
                var user = Membership.GetUser(Username);

                user.Email = Email;

                Membership.UpdateUser(user);
            }
            catch (Exception Ex)
            {
                _logger.WriteError(5000008, string.Format("Update User Email Failure | User: {0}", Username), Ex);
            }
        }

        public string ResetPassword(string Username, string Email)
        {
            string newPassword = null;

            try
            {
                //Update should use Email to get user...
                //To Do: ensure that user email is not duplicated at registration in membership..
                var User = Membership.GetUser(Username);

                if (User != null)
                {
                    StringBuilder strMessage = null;
                    var cust = custrepository.GetCustomerByUsername(Username);
                    //update User password...
                    newPassword = User.ResetPassword();

                    strMessage = new StringBuilder();
                    strMessage.AppendFormat("Dear {0}, You have requested that new password details be sent to you via email: Password:  {1}", cust.Firstname, newPassword);
                    strMessage.AppendLine("IMPORTANT: To ensure the safety of your account, we strongly recommend");
                    strMessage.AppendLine("you change your password the next time you log into the m-Diaspora web site.");
                    strMessage.AppendLine("Should you have any queries regarding the above, please do not hesitate to ");
                    strMessage.AppendLine("contact our support centre at ");
                    strMessage.AppendLine("http://www.mmitonline.com/live/contact.html");
                    strMessage.AppendLine("Kind regards,");
                    strMessage.AppendLine("m-Diaspora Customer Service");
                    strMessage.AppendLine("Tel: +234-809345-MMIT(6648)");
                    strMessage.AppendLine(": +234-805-1780-338");
                    strMessage.AppendLine("www.mmitonline.com");
                    strMessage.AppendLine("Changing the MMT Industry one kobo at a time..");

                    notificationManager._notificationType = NotificationType.EmailNotification;
                    notificationManager.SendPlainEmail(new string[] { User.Email }, "webmaster@mmitonline.com", "webmaster", "m-Diaspora : New Password", strMessage.ToString());

                    return newPassword;
                }
                else
                {
                    //throw exception...
                    throw new Exception("User not found!");
                }
            }
            catch (Exception Ex)
            {
                //Log Exception
                _logger.WriteError(5000009, string.Format("Password Reset Failure | User: {0}", Username), Ex);
            }

            return "";
        }
        #endregion
        #region Status Codes
        private static string ErrorCodeToString(MembershipCreateStatus createStatus)
        {
            // See http://go.microsoft.com/fwlink/?LinkID=177550 for
            // a full list of status codes.
            switch (createStatus)
            {
                case MembershipCreateStatus.DuplicateUserName:
                    return "User name already exists. Please enter a different user name.";

                case MembershipCreateStatus.DuplicateEmail:
                    return "A user name for that e-mail address already exists. Please enter a different e-mail address.";

                case MembershipCreateStatus.InvalidPassword:
                    return "The password provided is invalid. Please enter a valid password value.";

                case MembershipCreateStatus.InvalidEmail:
                    return "The e-mail address provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidAnswer:
                    return "The password retrieval answer provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidQuestion:
                    return "The password retrieval question provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidUserName:
                    return "The user name provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.ProviderError:
                    return "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                case MembershipCreateStatus.UserRejected:
                    return "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                default:
                    return "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
            }
        }
        #endregion

    }
}